package com.lime49.lockcrypt;
import com.lime49.lockcrypt.ui.AbstractDialog;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.filechooser.*;
import javax.swing.border.*;
import java.io.*;
import java.util.*;
import java.util.prefs.*;
import java.net.URL;

import com.jgoodies.looks.plastic.PlasticLookAndFeel;

/**
 * A form for changing program settings and options.
 */
public class FrmOptions extends AbstractDialog {
    private ResourceBundle lang;
    private boolean needDBRefresh = false,
                    resetDefaultAccounts = false;
    
    private ListSelectionModel typeListSelectionModel;
    private JButton btnAddType, btnEditType, btnRemoveType;
    private SpinnerNumberModel spnSecureClipDelayModel;
    private JSpinner spnSecureClipDelay, spnLockDelay;
    private JTextField txtDBLocation, txtDBHost, txtDBUser, txtDBName, txtAutoTypeHotkey;
    private JComboBox cLang, ddLaf;
    private JCheckBox chkSecureClipboard,chkMinimizeToTray, chkEnableFirefox, chkAutoType, chkAutoTypeCTRL, chkAutoTypeALT, chkAutoTypeSHIFT, chkAutoStart, chkAutoLock;
    private JPasswordField txtPassword, txtPassword2, passDBPass;
    private JComboBox cDBMode;
    private JPanel pnlModeFields;
    private AccType selectedType;
            
    private ArrayList<AccType> newTypes;
    private JList typeList;
    private DefaultListModel typeListModel;
    private Preferences prefs;
    private String setJCEKey,
                   externalSettingsFile;
            
    public FrmOptions(FrmMainWindow owner, ResourceBundle lang, Preferences prefs, ArrayList<AccType> types, String setJCEKey, String externalSettingsFile) {
        super(owner, lang.getString("OPTIONS"), true);
        this.lang = lang;
        this.newTypes = new ArrayList<AccType>();
        for(AccType type : types) {
            this.newTypes.add(type.clone());
        }
        //this.types = (ArrayList<AccType>)types.clone();
        this.prefs = prefs;
        this.setJCEKey = setJCEKey;
        this.externalSettingsFile = externalSettingsFile;
        
        this.typeListModel = new DefaultListModel();
        this.typeList = new JList(typeListModel);
        typeListSelectionModel = typeList.getSelectionModel();
        Insets INSETS1 = new Insets(1,1,1,1);
        GridBagConstraints c = new GridBagConstraints();
            c.insets = INSETS1;
        KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
        Action escapeAction = new AbstractAction() {
            // close the frame when the user presses escape
            public void actionPerformed(ActionEvent e) {
                thisDialog.dispose();
            }
        }; 
        this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
        this.getRootPane().getActionMap().put("ESCAPE", escapeAction);
        JPanel optionsContainer = new JPanel();
            optionsContainer.setLayout(new BorderLayout());
            this.setContentPane(optionsContainer);
        JTabbedPane optionsTabs = new JTabbedPane();
            optionsContainer.add(optionsTabs,BorderLayout.CENTER);
        OptionsListener optionsListener = new OptionsListener();
        
        JPanel tabAccountTypes = new JPanel();
            tabAccountTypes.setLayout(new BorderLayout());
            JPanel pnlManageTypes = new JPanel();
                pnlManageTypes.setLayout(new BorderLayout());
                pnlManageTypes.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED),lang.getString("MANAGETYPES")));
                JScrollPane typeListScroll = new JScrollPane(typeList);
                typeListScroll.setViewportBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
                typeListScroll.setBorder(BorderFactory.createEmptyBorder(0,10,10,5));
                typeListScroll.setPreferredSize(new Dimension(400,200));
                try {
                    typeList.setSelectedIndex(0);
                    typeList.ensureIndexIsVisible(0);
                } catch(Exception ex) { /* This should never happen, but just incase.. */ }
                pnlManageTypes.add(typeListScroll, BorderLayout.CENTER);
                
                TypeListListener typeListListener = new TypeListListener();
                typeListSelectionModel.addListSelectionListener(new TypeListSelectionListener());
                JPanel typeButtonContainer = new JPanel();
                typeButtonContainer.setLayout(new BoxLayout(typeButtonContainer,BoxLayout.Y_AXIS));
                typeButtonContainer.setBorder(BorderFactory.createEmptyBorder(0,5,0,10));
                Dimension BTNSIZE = new Dimension(300,40);
                btnAddType = new JButton(lang.getString("NEWTYPE"));
                    btnAddType.setMnemonic('N');
                    btnAddType.setActionCommand("add");
                    btnAddType.addActionListener(typeListListener);
                    btnAddType.setMaximumSize(BTNSIZE);
                    typeButtonContainer.add(btnAddType);
                typeButtonContainer.add(Box.createVerticalStrut(10));
                btnEditType = new JButton(lang.getString("EDIT"));
                    btnEditType.setMnemonic('E');
                    btnEditType.setActionCommand("edit");
                    btnEditType.addActionListener(typeListListener);
                    btnEditType.setMaximumSize(BTNSIZE);
                    typeButtonContainer.add(btnEditType);
                typeButtonContainer.add(Box.createVerticalStrut(10));
                btnRemoveType = new JButton(lang.getString("DELETE"));
                    btnRemoveType.setMnemonic('D');
                    btnRemoveType.setActionCommand("remove");
                    btnRemoveType.addActionListener(typeListListener);
                    btnRemoveType.setMaximumSize(BTNSIZE);
                    typeButtonContainer.add(btnRemoveType);
                pnlManageTypes.add(typeButtonContainer,BorderLayout.EAST);
                
                refreshTypeList("");
            tabAccountTypes.add(pnlManageTypes, BorderLayout.CENTER);
            
            JPanel pnlDefaultContainer = new JPanel();
                pnlDefaultContainer.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED),lang.getString("RESTOREDEFAULTS")));
                JButton btnDefTypes = new JButton(lang.getString("RESTOREDEFAULTTYPES"));
                    btnDefTypes.setActionCommand("defaulttypes");
                    btnDefTypes.addActionListener(optionsListener);
                    pnlDefaultContainer.add(btnDefTypes);
                JButton btnDefAccounts = new JButton(lang.getString("RESTOREDEFAULTACCOUNTS"));
                    btnDefAccounts.setActionCommand("defaultaccounts");
                    btnDefAccounts.addActionListener(optionsListener);
                    pnlDefaultContainer.add(btnDefAccounts);
            tabAccountTypes.add(pnlDefaultContainer,BorderLayout.SOUTH);
        
            c.insets = Constants.GLOBALINSETS;
            int fieldWidth = 12;
            JPanel pnlDBContainer = new JPanel(new GridBagLayout());
                pnlDBContainer.setMaximumSize(new Dimension(600,600));
                pnlDBContainer.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED),lang.getString("DATABASE")));
                int cury = 0;
                JTextPane lblDBmode = new JTextPane();
                    lblDBmode.setText(lang.getString("DBMODE_DESC"));
                    lblDBmode.setBackground(null);
                    lblDBmode.setEditable(false);
                    lblDBmode.setBorder(null);
                    Utils.setgrid(c, cury, 0, 2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, 1);
                    //pnlDBContainer.add(lblDBmode, DBModeConstraints);
                    cury++;
                JLabel lblMode = new JLabel(lang.getString("DBMODE"));
                    Utils.setgrid(c,cury,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.2);
                    pnlDBContainer.add(lblMode,c);
                String[] modes = {lang.getString("TXTFILE"), lang.getString("MYSQL")};
                cDBMode = new JComboBox(modes);
                    lblMode.setLabelFor(cDBMode);
                    lblMode.setDisplayedMnemonic('M');
                    cDBMode.addItemListener(new setDBModeListener());
                    Utils.setgrid(c,cury,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.PAGE_START,0.9);
                    pnlDBContainer.add(cDBMode,c);
                    //Utils.setgrid(DBModeConstraints,cury,2,1,1,GridBagConstraints.NONE,GridBagConstraints.WEST,0.1);
                    cury++;
                pnlModeFields = new JPanel(new CardLayout());
                    Utils.setgrid(c,cury,0,3,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                    cury++;
                    pnlDBContainer.add(pnlModeFields,c);
                    JPanel pnlTextFields = new JPanel(new GridBagLayout());
                        pnlModeFields.add(pnlTextFields,"text");
                        JLabel lblDBLocation = new JLabel(lang.getString("DBFILE"));
                            Utils.setgrid(c,0,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.3);
                            pnlTextFields.add(lblDBLocation,c);
                        txtDBLocation = new JTextField(fieldWidth);
                            lblDBLocation.setLabelFor(txtDBLocation);
                            lblDBLocation.setDisplayedMnemonic('F');
                            
                            Utils.setgrid(c,0,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,0.8);
                            pnlTextFields.add(txtDBLocation,c);
                        JButton btnBrowse = new JButton(lang.getString("BROWSE"));
                            lblDBLocation.setDisplayedMnemonic('B');
                            Utils.setgrid(c,0,2,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_END,0.1);
                            pnlTextFields.add(btnBrowse,c);
                            final Preferences fPrefs = prefs;
                            final ResourceBundle fLang = lang;
                            btnBrowse.addActionListener(new ActionListener() {
                                public void actionPerformed(ActionEvent e) {
                                    JFileChooser fc = new JFileChooser(fPrefs.get("setlastdblocation", System.getenv("USERPROFILE")));
                                        fc.setDialogTitle(fLang.getString("DBLOCATION"));
                                        FileNameExtensionFilter extLCDBs = new FileNameExtensionFilter(fLang.getString("LOCKCRYPTDATABASE"), "lce");
                                            fc.addChoosableFileFilter(extLCDBs);
                                            fc.setSelectedFile(new File(fPrefs.get("setfilename", System.getenv("APPDATA")+"\\LockCrypt\\LockCrypt.lce")));
                                        boolean gotFile = false;
                                        File newFileName = null;
                                        while(!gotFile) {
                                            int ret = fc.showSaveDialog(thisDialog);
                                            if(ret == JFileChooser.APPROVE_OPTION) {
                                                newFileName = fc.getSelectedFile();
                                                fPrefs.put("setlastdblocation",newFileName.getParent());
                                                try {
                                                    fPrefs.flush();
                                                } catch(Exception ignore) { }
                                                gotFile = true;
                                            } else if(ret == JFileChooser.CANCEL_OPTION) {
                                                return;
                                            }
                                        }
                                        try {
                                            txtDBLocation.setText(newFileName.getCanonicalPath());
                                        }catch(Exception ignore) {/**/}
                                }
                            });
                            if(externalSettingsFile == null) {
                                txtDBLocation.setText(prefs.get("setfilename", System.getenv("APPDATA")+"\\LockCrypt\\LockCrypt.lce"));
                            } else {
                                txtDBLocation.setText(externalSettingsFile);
                                txtDBLocation.setEnabled(false);
                                btnBrowse.setEnabled(false);
                                cDBMode.setEnabled(false);
                            }
                            c.weighty = 1;
                            Utils.setgrid(c,2,0,2,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                            pnlTextFields.add(Box.createVerticalGlue(),c);
                            c.weighty = 0;
                    JPanel pnlSQLFields = new JPanel(new GridBagLayout());
                        c.insets = new Insets(Constants.GLOBALINSETS.top, 0, Constants.GLOBALINSETS.bottom, 0);
                        pnlModeFields.add(pnlSQLFields,"mysql");
                        JLabel lblDBHost = new JLabel(lang.getString("DBHOST"));
                            Utils.setgrid(c,0,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.2);
                            pnlSQLFields.add(lblDBHost,c);
                        txtDBHost = new JTextField(fieldWidth);
                            lblDBHost.setLabelFor(txtDBHost);
                            lblDBHost.setDisplayedMnemonic('H');
                            txtDBHost.setText(prefs.get("setdbhost",""));
                            Utils.setgrid(c,0,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                            pnlSQLFields.add(txtDBHost,c);
                        JLabel lblDBUser = new JLabel(lang.getString("DBUSER"));
                            Utils.setgrid(c,1,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.2);
                            pnlSQLFields.add(lblDBUser,c);
                        txtDBUser = new JTextField(fieldWidth);
                            lblDBUser.setLabelFor(txtDBUser);
                            lblDBUser.setDisplayedMnemonic('U');
                            txtDBUser.setText(prefs.get("setdbuser",""));
                            Utils.setgrid(c,1,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                            pnlSQLFields.add(txtDBUser,c);
                        JLabel lblDBPass = new JLabel(lang.getString("DBPASS"));
                            Utils.setgrid(c,2,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.2);
                            pnlSQLFields.add(lblDBPass,c);
                        passDBPass = new JPasswordField(fieldWidth);
                            lblDBPass.setLabelFor(passDBPass);
                            lblDBPass.setDisplayedMnemonic('P');
                            passDBPass.setText(prefs.get("setdbpass",""));
                            Utils.setgrid(c,2,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                            pnlSQLFields.add(passDBPass,c);
                        JLabel lblDBName = new JLabel(lang.getString("DBDATABASE"));
                            Utils.setgrid(c,3,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.2);
                            pnlSQLFields.add(lblDBName,c);
                        txtDBName = new JTextField(fieldWidth);
                            lblDBName.setLabelFor(txtDBName);
                            lblDBName.setDisplayedMnemonic('D');
                            txtDBName.setText(prefs.get("setdbname",""));
                            Utils.setgrid(c,3,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                            pnlSQLFields.add(txtDBName,c);
                String dbMode = prefs.get("setdbmode", "text");
                if(dbMode.equals("text")) {
                    cDBMode.setSelectedItem(lang.getString("TXTFILE"));
                    ((CardLayout)(pnlModeFields.getLayout())).show(pnlModeFields, "text");
                } else if(dbMode.equals("mysql")) {
                    cDBMode.setSelectedItem(lang.getString("MYSQL"));
                    ((CardLayout)(pnlModeFields.getLayout())).show(pnlModeFields, "mysql");
                }
                c.insets = Constants.GLOBALINSETS;
                c.weighty = 1;
                Utils.setgrid(c,4,0,2,1,GridBagConstraints.BOTH,GridBagConstraints.CENTER,1);
                pnlDBContainer.add(Box.createVerticalGlue(),c);
                c.weighty = 0;

            JPanel pnlPassContainer = new JPanel(new GridBagLayout());
                pnlPassContainer.setMaximumSize(new Dimension(600,600));
                String passwordTitle = lang.getString("PASSWORD");
                pnlPassContainer.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED),(passwordTitle.endsWith(":") ? passwordTitle.substring(0,passwordTitle.length()-1) : passwordTitle)));
                
            JLabel lblPassword = new JLabel(lang.getString("PASSWORD"));
                Utils.setgrid(c,0,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.2);
                pnlPassContainer.add(lblPassword,c);
            txtPassword = new JPasswordField(fieldWidth);
                lblPassword.setLabelFor(txtPassword);
                lblPassword.setDisplayedMnemonic('s');
                txtPassword.setText(setJCEKey);
                Utils.setgrid(c,0,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.PAGE_START,1);
                pnlPassContainer.add(txtPassword,c);
            JLabel lblPassword2 = new JLabel(lang.getString("CONFIRMPASSWORD"));
                Utils.setgrid(c,1,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.2);
                pnlPassContainer.add(lblPassword2,c);
            txtPassword2 = new JPasswordField(fieldWidth);
                lblPassword2.setLabelFor(txtPassword2);
                lblPassword2.setDisplayedMnemonic('o');
                txtPassword2.setText(setJCEKey);
                Utils.setgrid(c,1,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.PAGE_START,1);
                pnlPassContainer.add(txtPassword2,c);
            if(setJCEKey == null) {
                txtPassword.setEnabled(false);
                txtPassword2.setEnabled(false);
                txtPassword.setOpaque(false);
                txtPassword2.setOpaque(false);
            } else {
                txtPassword.setEnabled(true);
                txtPassword2.setEnabled(true);
                txtPassword.setOpaque(true);
                txtPassword2.setOpaque(true);
            }
            c.weighty = 1;
            Utils.setgrid(c,2,0,2,1,GridBagConstraints.BOTH,GridBagConstraints.CENTER,1);
            pnlPassContainer.add(Box.createVerticalGlue(),c);
            c.weighty = 0;
            
            JPanel tabPreferences = new JPanel(new GridBagLayout());
                //tabPreferences.setLayout(new BoxLayout(tabPreferences,BoxLayout.Y_AXIS));
            JPanel pnlLanguage = new JPanel(new GridBagLayout());
                pnlLanguage.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), lang.getString("LOCALIZATION")));
                JLabel lblLanguage = new JLabel(lang.getString("LANGUAGE")+":");
                    Utils.setgrid(c,0,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.2);
                    pnlLanguage.add(lblLanguage, c);
                ArrayList<String> langShort = new ArrayList<String>();
                Set<String> abbrevs = Constants.LANGUAGES.keySet();
                Iterator iter = abbrevs.iterator();
                while(iter.hasNext()) {
                    langShort.add((String)iter.next());
                }
                cLang = new JComboBox(langShort.toArray());
                    lblLanguage.setLabelFor(cLang);
                    lblLanguage.setDisplayedMnemonic('L');
                    cLang.setSelectedItem(prefs.get("setlang", "en_GB"));
                    cLang.setRenderer(new LangRenderer());
                    cLang.setFont(Utils.getSafeFont("zh", false));
                    Utils.setgrid(c,0,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.PAGE_START,1);
                    pnlLanguage.add(cLang, c);
                JTextPane txtTranslatorsWanted = new JTextPane();
                    txtTranslatorsWanted.setText(lang.getString("TRANSLATORSNEEDED"));
                    txtTranslatorsWanted.setBackground(null);
                    txtTranslatorsWanted.setEditable(false);
                    txtTranslatorsWanted.setBorder(null);
                    Utils.setgrid(c,1,0,2,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                    pnlLanguage.add(txtTranslatorsWanted,c);
                    
            JPanel pnlAutoStart = new  JPanel(new FlowLayout(FlowLayout.LEADING));
                pnlAutoStart.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), lang.getString("AUTOSTART")));
                chkAutoStart = new JCheckBox("<HTML>"+lang.getString("STARTWITHWINDOWS")+"</HTML>");
                chkAutoStart.setMnemonic('a');
                if(prefs.getBoolean("setautostart", false)) {
                    chkAutoStart.setSelected(true);
                }
                pnlAutoStart.add(chkAutoStart);
                
            JPanel pnlAutoLock = new  JPanel(new FlowLayout(FlowLayout.LEADING));
                pnlAutoLock.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), lang.getString("AUTOLOCK")));
                chkAutoLock = new JCheckBox("<HTML>"+lang.getString("AUTOLOCKDESC")+"</HTML>");
                chkAutoLock.setMnemonic('t');
                pnlAutoLock.add(chkAutoLock);
                int lockAfter = prefs.getInt("setautolock", 600);
                if(lockAfter > 10) {
                    chkAutoLock.setSelected(true);
                    SpinnerModel spnModel  = new SpinnerNumberModel(lockAfter,11,6000,1);
                    spnLockDelay = new JSpinner(spnModel);
                } else {
                    SpinnerModel spnModel  = new SpinnerNumberModel(11,11,6000,60);
                    spnLockDelay = new JSpinner(spnModel);
                    spnLockDelay.setEnabled(false);
                }
                chkAutoLock.addItemListener(new ItemListener() {
                    public void itemStateChanged(ItemEvent e) {
                        spnLockDelay.setEnabled(chkAutoLock.isSelected());
                    }
                });
                spnLockDelay.setPreferredSize(new Dimension(50,20));
                spnLockDelay.setMaximumSize(new Dimension(50,20));
                    pnlAutoLock.add(spnLockDelay);
                JLabel lblAutoLock = new JLabel(lang.getString("SECONDS"));
                    pnlAutoLock.add(lblAutoLock);

            JPanel pnlAppearance = new JPanel(new GridBagLayout());
                pnlAppearance.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), lang.getString("APPEARANCE")));
                JLabel lblStyle = new JLabel(lang.getString("STYLE")+":");
                    Utils.setgrid(c,0,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.2);
                    pnlAppearance.add(lblStyle, c);
                ddLaf = new JComboBox(new String[] {
                        "JGoodies",
                        lang.getString("SYSTEM"),
                        lang.getString("CROSSPLATFORM")
                    });
                    lblLanguage.setLabelFor(ddLaf);
                    lblLanguage.setDisplayedMnemonic('S');
                    String laf = prefs.get("setlaf","JGoodies");
                    if(laf.equals("JGoodies")) {
                        ddLaf.setSelectedItem("JGoodies");
                    } else if(laf.equals(UIManager.getCrossPlatformLookAndFeelClassName())) {
                        ddLaf.setSelectedItem(lang.getString("CROSSPLATFORM"));
                    } else {
                        ddLaf.setSelectedItem(lang.getString("SYSTEM"));
                    }
                    Utils.setgrid(c,0,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.PAGE_START,1);
                    pnlAppearance.add(ddLaf, c);
                JLabel lblMinimizeToTray = new JLabel(lang.getString("MINIMIZETOTRAY")+":");
                    Utils.setgrid(c,1,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.2);
                    pnlAppearance.add(lblMinimizeToTray, c);
                chkMinimizeToTray = new JCheckBox(lang.getString("MINIMIZETOTRAYDESC"));
                    Utils.setgrid(c,1,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.PAGE_START,1);
                    chkMinimizeToTray.setSelected(prefs.getBoolean("setminimizetotray", true));
                    pnlAppearance.add(chkMinimizeToTray, c);
                    
                cury = -1;
                Utils.setgrid(c,++cury,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                tabPreferences.add(pnlAppearance, c);
                Utils.setgrid(c,++cury,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                tabPreferences.add(pnlLanguage, c);
                Utils.setgrid(c,++cury,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                tabPreferences.add(pnlAutoStart, c);
                Utils.setgrid(c,++cury,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                tabPreferences.add(pnlAutoLock, c);
                c.weighty = 1;
                Utils.setgrid(c,++cury,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                tabPreferences.add(Box.createVerticalGlue(),c );
                c.weighty = 0;
            
        JPanel tabSecureClipboard = new JPanel(new GridBagLayout());
            tabSecureClipboard.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED),lang.getString("SECURECLIPBOARD")));
            JTextPane txtAboutSecureClipboard = new JTextPane();
                txtAboutSecureClipboard.setText(lang.getString("SECURECLIPBOARD_DESC"));
                txtAboutSecureClipboard.setBackground(null);
                txtAboutSecureClipboard.setEditable(false);
                txtAboutSecureClipboard.setBorder(null);
                Utils.setgrid(c,0,0,2,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                tabSecureClipboard.add(txtAboutSecureClipboard,c);
            chkSecureClipboard = new JCheckBox("<HTML>"+lang.getString("SECURECLIPUSE")+"</HTML>");
                chkSecureClipboard.setMnemonic('e');
                if(prefs.getBoolean("setsecureclipboard", true)) {
                    chkSecureClipboard.setSelected(true);
                }
                Utils.setgrid(c,1,0,2,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.PAGE_START,1);
                tabSecureClipboard.add(chkSecureClipboard,c);
            spnSecureClipDelayModel = new SpinnerNumberModel(prefs.getInt("setsecureclipdelay", 10),1,3600,1);
            spnSecureClipDelay = new JSpinner(spnSecureClipDelayModel);
                Utils.setgrid(c,2,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.LINE_START,0.3);
                tabSecureClipboard.add(spnSecureClipDelay,c);
            JLabel lblSecureCliptime = new JLabel(lang.getString("SECURECLIPDELAY"));
                Utils.setgrid(c,2,1,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.LINE_START,0.7);
                tabSecureClipboard.add(lblSecureCliptime,c);

            c.weighty = 1;
            Utils.setgrid(c,3,0,2,1,GridBagConstraints.BOTH,GridBagConstraints.CENTER,1);
            tabSecureClipboard.add(Box.createVerticalGlue(),c);
        ImageIcon imgIcon = null;
        try {    
            URL urlExtLink = this.getClass().getResource("images/hyperlink.png");
            imgIcon = new ImageIcon(Toolkit.getDefaultToolkit().getImage(urlExtLink));
        } catch(Exception ignore) {}
        JPanel tabFirefox = new JPanel(new GridBagLayout());
            c.weighty = 0;
            tabFirefox.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED),lang.getString("FIREFOXEXTENSION")));
            JLabel lblFirefoxIcon = new JLabel();
                lblFirefoxIcon.setAlignmentX(Component.CENTER_ALIGNMENT);
                lblFirefoxIcon.setHorizontalAlignment(SwingConstants.CENTER);
                try {    
                    URL firefoxIconURL = this.getClass().getResource("images/lockcrypt-firefox.png");
                    ImageIcon firefoxIcon = new ImageIcon(Toolkit.getDefaultToolkit().getImage(firefoxIconURL));
                    lblFirefoxIcon.setIcon(firefoxIcon);
                } catch(Exception ignore) {}
                Utils.setgrid(c,0,0,2,1,GridBagConstraints.BOTH,GridBagConstraints.CENTER,1);
                tabFirefox.add(lblFirefoxIcon,c);
            JTextPane txtAboutFirefoxExtension = new JTextPane();
                txtAboutFirefoxExtension.setText(lang.getString("FIREFOXEXTENSION_DESC"));
                txtAboutFirefoxExtension.setBackground(null);
                txtAboutFirefoxExtension.setEditable(false);
                txtAboutFirefoxExtension.setBorder(null);
                Utils.setgrid(c,1,0,2,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                tabFirefox.add(txtAboutFirefoxExtension,c);
            chkEnableFirefox = new JCheckBox("<HTML>"+lang.getString("ENABLEFIREFOX")+"</HTML>");
                chkEnableFirefox.setMnemonic('o');
                if(prefs.getBoolean("setenablefirefox", true)) {
                    chkEnableFirefox.setSelected(true);
                }
                Utils.setgrid(c,2,0,2,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.PAGE_START,1);
                tabFirefox.add(chkEnableFirefox,c);
            JLabel lblFirefoxExtManual = new JLabel(lang.getString("FIREFOXMANUAL"), JLabel.CENTER);
                lblFirefoxExtManual.setForeground(Color.BLUE);
                lblFirefoxExtManual.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                lblFirefoxExtManual.addMouseListener(new MouseListener() {
                    public void mousePressed(MouseEvent e) {}
                    public void mouseReleased(MouseEvent e) {}
                    public void mouseEntered(MouseEvent e) {}
                    public void mouseExited(MouseEvent e) {}
                    public void mouseClicked(MouseEvent e) {
                       Utils.openURL("http://wiki.lime49.com/index.php?title=Firefox_Extension_%28LockCrypt%29");
                    }
                });
                Utils.setgrid(c,3,0,2,1,GridBagConstraints.VERTICAL,GridBagConstraints.LINE_START,1);
                tabFirefox.add(lblFirefoxExtManual,c);
            JLabel lblExtensionHomepage = new JLabel(lang.getString("FIREFOXMOZLINK"), JLabel.CENTER);
                lblExtensionHomepage.setForeground(Color.BLUE);
                lblExtensionHomepage.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                lblExtensionHomepage.addMouseListener(new MouseListener() {
                    public void mousePressed(MouseEvent e) {}
                    public void mouseReleased(MouseEvent e) {}
                    public void mouseEntered(MouseEvent e) {}
                    public void mouseExited(MouseEvent e) {}
                    public void mouseClicked(MouseEvent e) {
                       Utils.openURL("https://addons.mozilla.org/en-US/firefox/addon/8970");
                    }
                });
                Utils.setgrid(c,4,0,2,1,GridBagConstraints.VERTICAL,GridBagConstraints.LINE_START,1);
                tabFirefox.add(lblExtensionHomepage,c);
                lblFirefoxExtManual.setIcon(imgIcon);
            lblExtensionHomepage.setIcon(imgIcon);
            c.weighty = 1;
            Utils.setgrid(c,5,0,2,1,GridBagConstraints.BOTH,GridBagConstraints.CENTER,1);
            tabFirefox.add(Box.createVerticalGlue(),c);
            
        JPanel tabAutoType = new JPanel(new GridBagLayout());
            c.weighty = 0;
            cury = 0;
            tabAutoType.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED),lang.getString("AUTOTYPE")));
            JTextPane txtAutoTypeDesc = new JTextPane();
                txtAutoTypeDesc.setText(lang.getString("AUTOTYPEDESC"));
                txtAutoTypeDesc.setBackground(null);
                txtAutoTypeDesc.setEditable(false);
                txtAutoTypeDesc.setBorder(null);
                Utils.setgrid(c,cury,0,1,1,GridBagConstraints.BOTH,GridBagConstraints.PAGE_START,1);
                tabAutoType.add(txtAutoTypeDesc,c);
                cury++;
            JLabel lblGetDotNet = new JLabel(lang.getString("DLDOTNET"), JLabel.CENTER);
                lblGetDotNet.setForeground(Color.BLUE);
                lblGetDotNet.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                lblGetDotNet.addMouseListener(new MouseListener() {
                    public void mousePressed(MouseEvent e) {}
                    public void mouseReleased(MouseEvent e) {}
                    public void mouseEntered(MouseEvent e) {}
                    public void mouseExited(MouseEvent e) {}
                    public void mouseClicked(MouseEvent e) {
                       Utils.openURL("http://www.microsoft.com/downloads/details.aspx?FamilyId=333325FD-AE52-4E35-B531-508D977D32A6&displaylang=en");
                    }
                });
                lblGetDotNet.setIcon(imgIcon);
                Utils.setgrid(c,cury,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,1);
                tabAutoType.add(lblGetDotNet,c);
                cury++;
            chkAutoType = new JCheckBox("<HTML>"+lang.getString("ENABLEAUTOTYPE")+"</HTML>");
                chkAutoType.setMnemonic('e');
                if(prefs.getBoolean("setenableautotype", true)) {
                    chkAutoType.setSelected(true);
                }
                Utils.setgrid(c,cury,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                tabAutoType.add(chkAutoType,c);
                cury++;
            Container pnlHotkey = new Container();
                pnlHotkey.setLayout(new GridBagLayout());
                Utils.setgrid(c,cury,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
                tabAutoType.add(pnlHotkey,c);
                cury++;
                int curyInner = 0;
            JLabel lblAutoTypeHotkey = new JLabel(lang.getString("SHORTCUTKEY"));
                Utils.setgrid(c,curyInner,0,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_END,0.3);
                pnlHotkey.add(lblAutoTypeHotkey,c);
            txtAutoTypeHotkey = new JTextField(1);
                Utils.setgrid(c,curyInner,1,1,1,GridBagConstraints.NONE,GridBagConstraints.PAGE_START,0.1);
                pnlHotkey.add(txtAutoTypeHotkey,c);
            chkAutoTypeCTRL = new JCheckBox("<HTML>Ctrl</HTML>");
                Utils.setgrid(c,curyInner,2,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,0.9);
                pnlHotkey.add(chkAutoTypeCTRL,c);
                curyInner++;
            chkAutoTypeALT = new JCheckBox("<HTML>Alt</HTML>");
                Utils.setgrid(c,curyInner,2,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,0.9);
                pnlHotkey.add(chkAutoTypeALT,c);
                curyInner++;
            chkAutoTypeSHIFT = new JCheckBox("<HTML>Shift</HTML>");
                Utils.setgrid(c,curyInner,2,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,0.9);
                pnlHotkey.add(chkAutoTypeSHIFT,c);
                curyInner++;
            String setAutoTypeHotkey = prefs.get("setautotypehotkey", "ctrl+shift+T");
            try {
                if(setAutoTypeHotkey.indexOf("ctrl") >= 0) {
                    chkAutoTypeCTRL.setSelected(true);
                }
                if(setAutoTypeHotkey.indexOf("alt") >= 0) {
                    chkAutoTypeALT.setSelected(true);
                }
                if(setAutoTypeHotkey.indexOf("shift") >= 0) {
                    chkAutoTypeSHIFT.setSelected(true);
                }
                txtAutoTypeHotkey.setText(setAutoTypeHotkey.substring(setAutoTypeHotkey.length()-1));
            } catch(Exception ignore) {
                txtAutoTypeHotkey.setText("T");
            }
            
            if(!System.getProperty("os.name").toLowerCase().startsWith("windows")) {
                chkAutoType.setEnabled(false);
                txtAutoTypeHotkey.setEnabled(false);
                chkAutoTypeCTRL.setEnabled(false);
                chkAutoTypeALT.setEnabled(false);
                chkAutoTypeSHIFT.setEnabled(false);
                chkAutoStart.setEnabled(false);
            }
                
            c.weighty = 1;
            Utils.setgrid(c,cury,0,1,1,GridBagConstraints.BOTH,GridBagConstraints.CENTER,1);
            tabAutoType.add(Box.createVerticalGlue(),c);
            c.weighty = 0;
            
        JPanel buttonbox = new JPanel(new FlowLayout(FlowLayout.TRAILING));
            JButton btnok = new JButton(lang.getString("OK"));
                btnok.setActionCommand("saveoptions");
                btnok.addActionListener(optionsListener);
                buttonbox.add(btnok);
            JButton btncancel = new JButton(lang.getString("CANCEL"));
                btncancel.setActionCommand("cancel");
                btncancel.addActionListener(optionsListener);
                buttonbox.add(btncancel);
                btnok.setMinimumSize(Constants.MINSIZE);
                btnok.setPreferredSize(Constants.PREFSIZE);
                btnok.setMaximumSize(Constants.MAXSIZE);
                btncancel.setMinimumSize(Constants.MINSIZE);
                btncancel.setPreferredSize(Constants.PREFSIZE);
                btncancel.setMaximumSize(Constants.MAXSIZE);
        optionsContainer.add(buttonbox,BorderLayout.SOUTH);
        
        Icon icoDatabase = null, icoPassword = null, icoLocalization = null, icoAppearance = null,
             icoTypes = null, icoPreferences = null, icoClipboard = null, icoFirefox = null, icoAutoType = null;
        try {
            icoDatabase = new ImageIcon(this.getClass().getResource("images/database_16.png"), lang.getString("DATABASE"));
            icoPassword = new ImageIcon(this.getClass().getResource("images/password_16.png"), lang.getString("PASSWORD"));
            icoLocalization = new ImageIcon(this.getClass().getResource("images/language_16.png"), lang.getString("LOCALIZATION"));
            icoAppearance = new ImageIcon(this.getClass().getResource("images/appearance_16.png"), lang.getString("APPEARANCE"));
            icoTypes = new ImageIcon(this.getClass().getResource("images/types_16.png"), lang.getString("ACCOUNTTYPES"));
            icoPreferences = new ImageIcon(this.getClass().getResource("images/settings_16.png"), lang.getString("PREFERENCES"));
            icoClipboard = new ImageIcon(this.getClass().getResource("images/clipboard_16.png"), lang.getString("SECURECLIPBOARD"));
            icoFirefox = new ImageIcon(this.getClass().getResource("images/plugin_16.png"), lang.getString("FIREFOXEXTENSION"));
            icoAutoType = new ImageIcon(this.getClass().getResource("images/autotype_16.png"), lang.getString("AUTOTYPE"));
        } catch(Exception ignore) {}
        
        int tabIndex = -1;
        optionsTabs.addTab(lang.getString("ACCOUNTTYPES"), icoTypes, tabAccountTypes);
        optionsTabs.setMnemonicAt(++tabIndex, 'Y');
        optionsTabs.addTab(lang.getString("PREFERENCES"), icoPreferences, tabPreferences);
        optionsTabs.setMnemonicAt(++tabIndex, 'R');
        optionsTabs.addTab(lang.getString("DATABASE"), icoDatabase, pnlDBContainer);
        optionsTabs.setMnemonicAt(++tabIndex, 'D');
        optionsTabs.addTab((passwordTitle.endsWith(":") ? passwordTitle.substring(0,passwordTitle.length()-1) : passwordTitle), icoPassword, pnlPassContainer);
        optionsTabs.setMnemonicAt(++tabIndex, 'P');
        optionsTabs.addTab(lang.getString("SECURECLIPBOARD"), icoClipboard, tabSecureClipboard);
        optionsTabs.setMnemonicAt(++tabIndex, 'C');
        optionsTabs.addTab(lang.getString("FIREFOXEXTENSION"), icoFirefox, tabFirefox);
        optionsTabs.setMnemonicAt(++tabIndex, 'F');
        optionsTabs.addTab(lang.getString("AUTOTYPE"), icoAutoType, tabAutoType);
        optionsTabs.setMnemonicAt(++tabIndex, 'T');
        
        this.getRootPane().setDefaultButton(btnok);
        this.setMinimumSize(new Dimension(400,300));
        this.setPreferredSize(new Dimension(500,550));
        this.setMaximumSize(new Dimension(800,800));
        this.pack();
        this.setLocationRelativeTo(owner);
        this.setVisible(true);
    }
    
    private void saveOptions() {
        prefs.put("setdbhost", txtDBHost.getText());
        prefs.put("setdbuser", txtDBUser.getText());
        prefs.put("setdbpass", new String(passDBPass.getPassword()));
        prefs.put("setdbname", txtDBName.getText());
        prefs.put("setlang", (String)cLang.getSelectedItem());
        prefs.putInt("setsecureclipdelay", (Integer)spnSecureClipDelay.getValue());
        prefs.putBoolean("setsecureclipboard", chkSecureClipboard.isSelected());
        //prefs.putBoolean("setfirstload", false);
        prefs.put("setlaf", (String)ddLaf.getSelectedItem());
        prefs.putBoolean("setenablefirefox", chkEnableFirefox.isSelected());
        if(externalSettingsFile == null) { // default db location. Don't overwrite if an external file has been specified
            if(cDBMode.getSelectedItem().toString().equals(lang.getString("TXTFILE"))) {
                prefs.put("setdbmode", "text");
            } else if(cDBMode.getSelectedItem().toString().equals(lang.getString("MYSQL"))) {
                prefs.put("setdbmode", "mysql");
            }
            if(cDBMode.getSelectedItem().toString().equals(lang.getString("TXTFILE")) && txtDBLocation.getText().isEmpty()) {
                JOptionPane.showMessageDialog(this, lang.getString("ERR_DBLOCBLANK"), lang.getString("ERROR"), JOptionPane.ERROR_MESSAGE);
                return;
            } else {
                prefs.put("setfilename", txtDBLocation.getText());
            }
        }
        if(setJCEKey != null) {
            String pass1 = new String(txtPassword.getPassword());
            String pass2 = new String(txtPassword2.getPassword());
            if(!pass1.equals(pass2)) {
                JOptionPane.showMessageDialog(this, lang.getString("ERR_PASSNOMATCH_DESC"), lang.getString("ERR_PASSNOMATCH"), JOptionPane.ERROR_MESSAGE);
                return;
            } else if(pass1.isEmpty() && !setJCEKey.isEmpty()) {
                if(JOptionPane.showConfirmDialog(this, lang.getString("ERR_PASSBLANK_DESC"), lang.getString("ERR_PASSBLANK"), JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
                    return;
                }
            }
            setJCEKey = pass1;
            needDBRefresh = true;
        }
        String lafName = (String)ddLaf.getSelectedItem();
        if(lafName.equals("JGoodies")) {
            prefs.put("setlaf", "JGoodies");
        } else if(lafName.equals(lang.getString("SYSTEM"))) {
            prefs.put("setlaf", UIManager.getSystemLookAndFeelClassName());
        } else {
            prefs.put("setlaf", UIManager.getCrossPlatformLookAndFeelClassName());
        }
        prefs.putBoolean("setminimizetotray",chkMinimizeToTray.isSelected());
        prefs.putBoolean("setenableautotype",chkAutoType.isSelected());
        prefs.putBoolean("setautostart",chkAutoStart.isSelected());
        if(System.getProperty("os.name").toLowerCase().startsWith("windows")) {
            try {
                int handle = RegUtil.RegOpenKey(RegUtil.HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", RegUtil.KEY_ALL_ACCESS)[RegUtil.NATIVE_HANDLE];
                if(chkAutoStart.isSelected()) {
                    String jar = "", 
                           jarPath, 
                           loc;
                    try {
                        jar = Utils.getJARPath();
                        if(!jar.endsWith(".exe") && jar.length() > 3) {
                            jar = jar+"LockCrypt.jar";
                        }
                    } catch(Exception ignore) { }
                    try {
                        int installLocationHandle = RegUtil.RegOpenKey(RegUtil.HKEY_CURRENT_USER, "SOFTWARE\\LockCrypt", RegUtil.KEY_READ)[RegUtil.NATIVE_HANDLE];
                        loc = new String(RegUtil.RegQueryValueEx(installLocationHandle, "")).trim();
                        File lcFile = new File(loc+"\\LockCrypt.exe");
                        if(lcFile.exists()) {
                            jarPath = lcFile.getPath();
                        } else {
                            lcFile = new File(loc+"\\LockCrypt.jar");
                            if(lcFile.exists()) {
                                jarPath = lcFile.getPath();
                            } else {
                                jarPath = jar.replace("/", "\\");
                            }
                        }
                    } catch(Exception ignore) { // key doesn't exist (lockcrypt not installed)
                        jarPath = jar.replace("/", "\\");
                    }
                    if(jarPath.trim().length() < 6) {
                        JOptionPane.showMessageDialog(thisDialog, lang.getString("ERROR")+" #227: "+lang.getString("ERR_FINDLOCKCRYPT"), lang.getString("ERROR"), JOptionPane.ERROR_MESSAGE);
                    } else {
                        RegUtil.RegSetValueEx(handle, "LockCrypt", "\""+jarPath+"\"");
                    }
                } else {
                    RegUtil.RegDeleteValue(handle, "LockCrypt");
                }
            } catch(Exception ex) {
                JOptionPane.showMessageDialog(thisDialog, lang.getString("ERROR")+" #228: "+lang.getString("ERR_WRITEREGISTRY")+"\n"+ex.getLocalizedMessage(), lang.getString("ERROR"), JOptionPane.ERROR_MESSAGE);
            }
        }
        StringBuffer autoTypeHotkey = new StringBuffer();
        if(chkAutoTypeCTRL.isSelected()) {
            autoTypeHotkey.append("ctrl+");
        }
        if(chkAutoTypeALT.isSelected()) {
            autoTypeHotkey.append("alt+");
        }
        if(chkAutoTypeSHIFT.isSelected()) {
            autoTypeHotkey.append("shift+");
        }
        autoTypeHotkey.append(txtAutoTypeHotkey.getText().charAt(0));
        prefs.put("setautotypehotkey", autoTypeHotkey.toString());
        int lockDelay = (Integer)spnLockDelay.getValue();
        if(chkAutoLock.isSelected() && lockDelay > 10) {
            prefs.putInt("setautolock", lockDelay);
        } else {
            prefs.putInt("setautolock", 0);
        }
        try {
            prefs.flush();
        } catch(Exception ignore) {}
    }

    /**
     * Returns the list of Account Types
     * @return The list of Account Types
     */
    public ArrayList<AccType> getTypes() {
        return this.newTypes;
    }

    /**
     * Returns the encryption password
     * @return The encryption password
     */
    public String getJCEKey() {
        return this.setJCEKey;
    }

    /**
     * Returns true if the database needs to be reloaded because of a changed password
     * @return True if the database needs to be reloaded because of a changed password, otherwise false
     */
    public boolean getNeedDBRefresh() {
        return this.needDBRefresh;
    }

    /**
     * Returns true if the default accounts should be restored
     * @return True if the default accounts should be restored, otherwise false
     */
    public boolean getResetDefaultAccounts() {
        return this.resetDefaultAccounts;
    }
    
    /**
     * Refreshes the list of account types in the options dialog box. Selects the item with the name matching <i>oldname</i>
     * so the selection doesn't jump.
     * @param oldname The name of the previously selected type.
     */
    private void refreshTypeList(String oldname) {
        int pos = 0;
        if(!oldname.equals("")) {
            //pos = Utils.getTypeIndex(oldname,newTypes,"list");
            pos = typeListModel.indexOf(oldname);
        }
        typeListModel.clear();
        Collections.sort(newTypes, new TypeComparator());
        for(AccType type : newTypes) {
            if(!type.isDeleted) {
                typeListModel.addElement(type.getName());
            }
        }
        int listSize = typeListModel.size();
        if(listSize > 0) {
            if(listSize > pos) {
                typeList.setSelectedIndex(pos);
                typeList.ensureIndexIsVisible(pos);
            } else {
                typeList.setSelectedIndex(listSize-1);
                typeList.ensureIndexIsVisible(listSize-1);
            }
        }
    }
    
    /**
     * Shows the 'Add Type' or 'Edit Type' dialog box.
     * @param type The type to be edited. If the type name is empty (new AccType() has been
     *             used to instanciate this type, a new type will be created.
     */
    private void showAddTypeDialog(AccType type, boolean editing) {
        FrmAddType frmAddType = new FrmAddType(this, lang, editing, type, newTypes);
        if(frmAddType.getResult() == JOptionPane.OK_OPTION) {
            int oldindex;
            String typeName = frmAddType.getTypeName();
            String typeFieldsInp = frmAddType.getTypeFieldsInp();
            boolean showNotes = frmAddType.getShowNotes();
            if(Utils.getTypeIndex(typeName, newTypes, "types") >= 0) { 
                /* does not exist in the list, but has been deleted since the database has 
                 * been synchronised, so still exists in 'types' arraylist.
                 * Name must be the same because the type name exists */
                newTypes.remove(Utils.getTypeIndex(typeName,newTypes,"types"));
            }
            if(editing) {
                oldindex = Utils.getTypeIndex(type.getName(), newTypes,"list");
                if(!selectedType.getName().equals(typeName)) {
                    // different name, have to delete the old record and create a new one
                    newTypes.get(Utils.getTypeIndex(selectedType.getName(), newTypes,"types")).delete();
                }
            } else { // command is add
                oldindex = typeListModel.size();
            }
            ArrayList<String> typeFieldsAry = new ArrayList<String>();
            String[] firstPass = typeFieldsInp.split(",");
            for(String firstPassVal : firstPass) {
                String[] secondPass = firstPassVal.split("\n");
                for(String fieldName : secondPass) {
                    typeFieldsAry.add(fieldName.trim());
                }
            }
            String[] typeFields = new String[typeFieldsAry.size()];
            typeFieldsAry.toArray(typeFields);
            newTypes.add(new AccType(typeName, typeFields, true, false, showNotes));
            refreshTypeList(typeName);
        }
    }
    
    /**
     * Removes the type with the specified name by marking it as deleted.
     * @param type The name of the type to be removed.
     */
    private void removeType(String type) {
        int index = Utils.getTypeIndex(type, newTypes,"types");
        int listIndex = typeListModel.indexOf(type);
        newTypes.get(index).delete();
        if(listIndex < typeListModel.size()) {
            refreshTypeList(typeListModel.getElementAt(listIndex).toString());
        } else {
            refreshTypeList(typeListModel.getElementAt(typeListModel.getSize()).toString());
        }
    }
    
    /**
     * Resets the default list of account types
     */
    private void resetDefaultTypes() {
        LinkedHashMap<String, String[]> typeMap = new LinkedHashMap<String,String[]>();
        typeMap.put(lang.getString("BLANK"), new String[] {});
        typeMap.put(lang.getString("CONTACT"), new String[] {"First Name", "Last Name", "House Number", "Line 1", "Line 2","Line 3", "City", "State/Province", "Post Code/ZIP", "Country", "Email Address", "Phone" });
        typeMap.put(lang.getString("BANKACCOUNT"), new String[] {"Bank","Branch", "Sort Code", "Account Number", "PIN", "If Lost", "Phone", "IBAN"});
        typeMap.put(lang.getString("COMBINATIONLOCK"), new String[] {"Location", "Code"});
        typeMap.put(lang.getString("CREDITCARD"),new String[] {"Card Number", "First Name", "Last Name", "Issue", "Start Date", "Expiry Date", "PIN", "CCV", "If Lost"});
        typeMap.put(lang.getString("DRIVINGLICENSE"), new String[] {"Name", "Valid from", "Valid to", "Issuing Authority","License Number", "Category"});
        typeMap.put(lang.getString("MEMBERSHIP"), new String[] {"Company", "Membership number", "Expires", "Phone"});
        typeMap.put(lang.getString("EMAILACC"), new String[] {"Login", "Password", "POP3", "SMTP", "IMAP"});
        typeMap.put(lang.getString("PRESCRIPTION"), new String[] {"Drug", "Dosage", "Frequency", "Brand", "Doctor", "Pharmacy", "Phone"});
        typeMap.put("MasterCard", new String[] {"Card Number", "First Name", "Last Name", "Issue", "Start Date", "Expiry Date", "PIN", "CCV", "If Lost"});
        typeMap.put("Maestro", new String[] {"Card Number", "First Name", "Last Name", "Issue", "Expiry Date", "PIN", "CCV", "If Lost"});
        typeMap.put(lang.getString("SERIAL"), new String[] {"Company", "Serial Number", "Purchased", "Email"});
        typeMap.put("VISA", new String[] {"Card Number", "First Name", "Last Name", "Issue", "Start Date", "Expiry Date", "PIN", "CCV", "If Lost"});
        
        for(Object typeName : typeMap.keySet()) {
            int position = Utils.getTypeIndex(typeName.toString(),newTypes,"types");
            if(position >= 0) {
                newTypes.get(position).isDeleted = false;
            } else {
                newTypes.add(new AccType(typeName.toString(), (String[])typeMap.get(typeName), true, false, true));
            }
        }
        if(Utils.getTypeIndex(lang.getString("WEBSITE").toString(),newTypes,"list") < 0) {
            AccType websiteType = new AccType(lang.getString("WEBSITE"), new String[] { "~}uURL", "Username", "~}*Password", "Registered Email" }, true, true, true);
            websiteType.setID("__pass");
            newTypes.add(websiteType);
        }
        refreshTypeList("");
    }
    
    /**
     * Checks that all settings entered are valid.
     * @return True if the settings entered are valid, otherwise false.
     */
    private boolean validateOptions() {
        boolean valid = true;
        if(txtAutoTypeHotkey.getText().length() > 0 && !Character.isLetter(txtAutoTypeHotkey.getText().charAt(0))) {
            JOptionPane.showMessageDialog(thisDialog, lang.getString("ERR_INVALIDSHORTCUT"), lang.getString("ERROR"), JOptionPane.ERROR_MESSAGE);
            valid = false;
        }
        return valid;
    }

    class OptionsListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            String cmd = e.getActionCommand();
            if(cmd.equals("saveoptions") && validateOptions()) {
                saveOptions();
                result = JOptionPane.OK_OPTION;
                thisDialog.dispose();
            } else if(cmd.equals("cancel")) {
                thisDialog.dispose();
            } else if(cmd.equals("defaulttypes")) {
                resetDefaultTypes();
            } else if(cmd.equals("defaultaccounts")) {
                resetDefaultAccounts = true;
            }
        }
    }
    class TypeListListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            String cmd = e.getActionCommand();
            if(cmd.equals("add")) {
                showAddTypeDialog(new AccType(), false);
            } else if(cmd.equals("remove")) {
                if(newTypes.get(Utils.getTypeIndex(typeList.getSelectedValue().toString(),newTypes,"visible")).getIsProtected()) {
                    AccType t = newTypes.get(Utils.getTypeIndex(typeList.getSelectedValue().toString(),newTypes,"visible"));
                    JOptionPane.showMessageDialog(null, lang.getString("ERR_PROTECTEDTYPE"), lang.getString("ERROR"), JOptionPane.ERROR_MESSAGE);
                } else {
                    removeType(typeList.getSelectedValue().toString());
                }
            } else if(cmd.equals("edit")) {
                if(newTypes.get(Utils.getTypeIndex(typeList.getSelectedValue().toString(),newTypes,"visible")).getIsProtected()) {
                    JOptionPane.showMessageDialog(null, lang.getString("ERR_PROTECTEDTYPE"), lang.getString("ERROR"), JOptionPane.ERROR_MESSAGE);
                } else {
                    showAddTypeDialog(selectedType, true);
                }
            }
        }
    }
    
    class setDBModeListener implements ItemListener {
        // Switches cards when the value of JComboBox 'cDBMode' changes
        public void itemStateChanged(ItemEvent e) {
            CardLayout modeCards = (CardLayout)(pnlModeFields.getLayout());
            if(cDBMode.getSelectedItem().equals(lang.getString("TXTFILE"))) {
                modeCards.show(pnlModeFields, "text");
            } else if(cDBMode.getSelectedItem().equals(lang.getString("MYSQL"))) {
                modeCards.show(pnlModeFields, "mysql");
            }
        }
    }
    
    class TypeListSelectionListener implements ListSelectionListener {
        public void valueChanged(ListSelectionEvent e) {
            if(!e.getValueIsAdjusting()) {
                if(typeListModel.size() > 0) {
                    btnEditType.setEnabled(true);
                    btnRemoveType.setEnabled(true);
                    for(int i=e.getFirstIndex();i<=e.getLastIndex();i++) {
                        if(((ListSelectionModel)e.getSource()).isSelectedIndex(i)) {
                            selectedType = newTypes.get(Utils.getTypeIndex((String)typeList.getSelectedValue(),newTypes,"types"));
                        }
                    }
                } else {
                    btnEditType.setEnabled(false);
                    btnRemoveType.setEnabled(false);
                }
            }
        }
    }
    class TypeComparator implements Comparator<AccType> {
        public int compare(AccType someType, AccType otherType) {
            AccType t1 = someType;
            AccType t2 = otherType;
            return t1.getName().compareTo(t2.getName());
        }
    }
    
    /**
     * Renders the flags for the languages combo box
     */
    class LangRenderer extends JLabel implements ListCellRenderer {
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            setHorizontalTextPosition(SwingConstants.RIGHT);
            String nativeLang = Constants.LANGUAGES.get(value);
            setText(nativeLang);
            ImageIcon flagIcon = null;
            try {
                URL flagURL = this.getClass().getResource("images/flags/"+value+"_small.png");
                flagIcon = new ImageIcon(flagURL, nativeLang);
            } catch(Exception ignore) { /**/ }
            setIcon(flagIcon);
            if(cellHasFocus) {
                setBackground(PlasticLookAndFeel.getMenuItemSelectedBackground());
            } else if(isSelected) {
                setBackground(PlasticLookAndFeel.getMenuItemSelectedBackground());
            }
            return this;
        }
    }
}
